// Web GUI Processes

import std.concurrency, std.stdio, std.string, std.format, std.array, std.conv, std.socket, std.json;

import Registry.registry;
import Definitions.msgCatalogue;
import Definitions.procNames;
import WsServer.listener;
import WsServer.ws;
import WsServer.pandata;

// Main processing loop for the dsp
//===========================================================================================
Tid init_web() {
    // A web sockets thread
    // Bi-directional data for the UI

    auto webtid = spawn(&listnerproc);
    auto wsguievtid = spawn(&wsguievtproc);
    return wsguievtid;
}

void wsguievtproc() {

    // Create the class that will read rx blocks from the device.
    writeln("Creating WS GUI Event Proc");
    auto owsguievt = new WsGuiEvt();
    owsguievt.process();
}

//===========================================================================================
// Incoming messages for all connected users
class WsGuiEvt {

    Pan pan;

    this() {
        this.pan = new Pan();
    }

    void process() {
        // Sit in the receiver loop processing requests
        while (true) {
            //writeln("Entering main loop");
            receive(
                &this.set_freq,
                &this.pan_data
            );
        }
    }

    //-------------------------------------------------------------------------------
    // Frequency set
    // float - freq
    void set_freq(M_SET_FREQ discriminator, double freq) {

        // Set the pan centre freq
        this.pan.set_freq(freq);

        // Send the freq change to the gui
        auto writer = appender!string();
        formattedWrite(writer, "%f", freq);
        auto data = writer.data;
        auto filled = zfill(data, 10);
        auto json = JSONValue();
        // This is the only way I can get anything to work
        // Attempting a dictionary crashes the thread
        // This is a string array which does get through and can be parsed
        // This is the wrong way to create it, should be possible to do directly.
        auto val = "[\"freq\",\"" ~ filled ~ "\"]";
        //json = parseJSON(val);

        Socket[] socks = CSockets.getSockets();
        foreach(sock; socks) {
            ubyte[] ub = 0x00 ~ cast(ubyte[])val ~ 0xff;
            //writeln("Sending: ", ub);
            sock.send(ub);
        }
    }

    void pan_data(M_PAN_DATA discriminator, immutable (float)[] data) {

        // Now we have an array of floats to get across, oh joy!
        //writeln(data);
        Socket[] socks;
        ubyte[] ub;

        this.pan.data_update(data);

        // Horizontal grid
        auto h_grid = this.pan.getPowerOverlay();
        //writeln(h_grid);
        string h;
        foreach(db, value; h_grid) {
            //writeln(db, value);
            h = h ~ ",\"" ~ to!string(db) ~ "\"," ~
            to!string(value.field[0].x) ~ "," ~ to!string(value.field[0].y) ~ "," ~
            to!string(value.field[1].x) ~ "," ~ to!string(value.field[1].y) ~ "," ~
            to!string(value.field[2].x) ~ "," ~ to!string(value.field[2].y);
        }
        auto h_plot = "[\"h_plot\"" ~ h ~ "]";
        //writeln(h_plot);
        socks = CSockets.getSockets();
        foreach(sock; socks) {
            ub = 0x00 ~ cast(ubyte[])h_plot ~ 0xff;
            sock.send(ub);
        }

        // Vertical grid
        auto v_grid = this.pan.getFreqOverlay();
        //writeln(v_grid);
        string v;
        foreach(f, value; v_grid) {
            //writeln(f, value);
            v = v ~ ",\"" ~ to!string(f) ~ "\"," ~
            to!string(value.field[0].x) ~ "," ~ to!string(value.field[0].y) ~ "," ~
            to!string(value.field[1].x) ~ "," ~ to!string(value.field[1].y) ~ "," ~
            to!string(value.field[2].x) ~ "," ~ to!string(value.field[2].y);
        }
        auto v_plot = "[\"v_plot\"" ~ v ~ "]";
        //writeln(v_plot);
        socks = CSockets.getSockets();
        foreach(sock; socks) {
            ub = 0x00 ~ cast(ubyte[])v_plot ~ 0xff;
            sock.send(ub);
        }

        // Plot
        auto mag_pts = this.pan.getPlot();
        // This is an int array
        //writeln(pan_pts[20].y);
        string mags;
        foreach(ref mag; mag_pts) {
            //to!string(mag)
            //mags = mags ~ ",\"" ~ to!string(mag) ~ "\"";
            mags = mags ~ "," ~ to!string(mag);
        }

        auto pan = "[\"pan\"" ~ mags ~ "]";
        socks = CSockets.getSockets();

        foreach(sock; socks) {
            ub = 0x00 ~ cast(ubyte[])pan ~ 0xff;
            sock.send(ub);
        }
    }
}
